﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Driver.Builders;
using MongoDB.Bson.Serialization;

using publicLibrary;
namespace asMeishi.web.Models
{
    using Classes;
    using Filter;
    /// <summary>
    /// 店基础类
    /// </summary>

    public class shop : MongoDocument
    {
        /// <summary>
        /// 店名
        /// </summary>
        [BsonElement("N")]
        public string name { get; set; }
        /// <summary>
        /// 其他店名(中文)
        /// </summary>
        [BsonElement("NC")]
        public string nameCN { get; set; }
        /// <summary>
        /// 店名（英文）
        /// </summary>
        [BsonElement("NE")]
        public string nameEN { get; set; }
        /// <summary>
        /// 地址-市
        /// </summary>
        public string city { get; set; }
        /// <summary>
        /// 地址-区/县
        /// </summary>
        public string area { get; set; }
        /// <summary>
        /// 地址-街道/村
        /// </summary>
        public string street { get; set; }
        /// <summary>
        /// 经纬坐标
        /// </summary>
        [BsonElement("ANL")]
        public double[] longitudeAndLatitude  { get; set; }
        /// <summary>
        /// 地址
        /// </summary>
        [BsonElement("AS")]
        public string addressStr { get; set; }
        /// <summary>
        /// 交通路线
        /// </summary>
        [BsonElement("BP")]
        public string busPath { get; set; }
        /// <summary>
        /// 电话
        /// </summary>
        [BsonElement("TP")]
        public string telephone { get; set; }
        /// <summary>
        /// 主营
        /// </summary>
        [BsonElement("FC")]
        public string foodStyle { get; set; } //多标签：面食，烧烤，火锅，自助，家常菜，特色小吃，快餐，饮料，咖啡，茶餐，川菜，湘菜，土家菜，潮粤菜，东北菜，江浙菜,清真，日餐，韩餐，西餐
        /// <summary>
        /// 主营str
        /// </summary>
        [BsonElement("FCS")]
        public List<string> foodStyleList { get; set; } //多标签：面食，烧烤，火锅，自助，家常菜，特色小吃，快餐，饮料，咖啡，茶餐，川菜，湘菜，土家菜，潮粤菜，东北菜，江浙菜,清真，日餐，韩餐，西餐

        /// <summary>
        /// 专属菜系
        /// </summary>
        [BsonElement("OC")]
        public string foodOtherClass { get; set; }//多标签：川菜，湘菜，土家菜，潮粤菜，东北菜，江浙菜,清真，日餐，韩餐，西餐
        /// <summary>
        /// 硬件条件标签
        /// </summary>
        [BsonElement("UT")]
        public List<string> utilityTags { get; set; }//多标签：可外卖 ，有停车位，有赠送，有折扣
        /// <summary>
        /// 标签
        /// </summary>
        [BsonElement("T")]
        public string tags { get; set; }//很好,吃

        /// <summary>
        /// 网址
        /// </summary>
        [BsonElement("W")]
        public string web { get; set; }
        /// <summary>
        /// 简介
        /// </summary>
        [BsonElement("I")]
        public string intro { get; set; }
        /// <summary>
        /// 适合 （如： 聚会）
        /// </summary>
        public string fit { get; set; }
        /// <summary>
        /// 总店分店，0，独一家，1：连锁，2：总店
        /// </summary>
        [BsonElement("H")]
        public int head { get; set; }
        /// <summary>
        /// 味道(打分)
        /// </summary>
        [BsonElement("Q")]
        public double quality { get; set; }
        /// <summary>
        /// 服务(打分)
        /// </summary>
        [BsonElement("V")]
        public double service { get; set; }
        /// <summary>
        /// 性价比(打分)
        /// </summary>
        [BsonElement("E")]
        public double priceQuality { get; set; }
        /// <summary>
        /// 价格
        /// </summary>
        [BsonElement("C")]
        public double cost { get; set; }
        /// <summary>
        /// 店大小
        /// </summary>
        [BsonElement("S")]
        public int size { get; set; }
        /// <summary>
        /// 最后修改时间
        /// </summary>
        [BsonElement("LT")]
        [BsonDateTimeOptions(Kind = DateTimeKind.Local)]
        public DateTime lasttime { get; set; }
        /// <summary>
        /// 记录创建时间
        /// </summary>]
        [BsonElement("CT")]
        [BsonDateTimeOptions(Kind = DateTimeKind.Local)]
        public DateTime createtime { get; set; }
        /// <summary>
        /// 图片文件名的数组,**是用string还是string[]，测试中
        /// </summary>
        [BsonElement("PL")]
        public List<string> picUrlList { get; set; }

        //[BsonDefaultValue(new List<string>())]
        [BsonElement("F")]
        public List<string> food { get; set; }
        /// <summary>
        /// 评分人数
        /// </summary>
        [BsonElement("SN")]
        public int score_number { get; set; }
        /// <summary>
        /// 总分
        /// </summary>
        [BsonElement("TS")]
        public int total_score { get; set; }
        ///总分平均值
        [BsonElement("SS")]
        public double sum_score { get; set; }
        /// <summary>
        /// 消费人数
        /// </summary>
        [BsonElement("TN")]
        public int cost_number { get; set; }
        [BsonElement("WN")]
        public int view_number { set; get; }
        [BsonElement("MN")]
        public int comment_number { set; get; }
        //最后编辑者 
        [BsonElement("LU")]
        public ObjectId lastReviseUser { set; get; }
        //创建者
        public ObjectId createUserId { set; get; }
        //优惠
        public List<sale> sales { get; set; }

        ///// <summary>
        ///// 消费支持
        ///// </summary>
        //[BsonElement("Y")]
        //public string pay { set; get; }

        /// <summary>
        /// 合作，同盟 唯一样
        /// </summary>
        [BsonElement("AL")]
        public string ally { set; get; }

        /// <summary>
        /// 环境["01","02"]
        /// </summary>
        [BsonElement("EV")]
        public string environment { set; get; }

        /// <summary>
        /// 发布完成步骤，莫认为0：新建，5为发布，中间有1,2,3,4
        /// </summary>
        [BsonDefaultValue(0)]
        [BsonElement("RL")]
        public int releaseStep { set; get; }
        /// <summary>
        /// 团购
        /// </summary>
        [BsonElement("GP")]
        public bool groupPurchase { set; get; }
        /// <summary>
        /// 锁
        /// </summary>
        [BsonElement("IL")]
        public Boolean isLock{set;get;}
        public string bak1 { set; get; }
        public string bak2 { set; get; }

        [BsonDefaultValue(true)]
        public Boolean able { set; get; }



    }
    //店扩展类**********************

    /// <summary>
    ///促销类
    /// <summary>
    public class sale : MongoDocument{
        public string content { set; get; }
        public Boolean able { set; get; }
        public ObjectId userId { set;get; }
        public string userName{set;get;}
        public int recommendCount{ set; get; }
        public DateTime datetime { set; get; }
        public int type { set;get; }



    }
    /// <summary>
    /// 店控制类
    /// </summary>

    public class shopC
    {
        public DataSession<MongoDataContext, shop> db = new DataSession<MongoDataContext, shop>();
        /// <summary>
        /// 新建一个shop实例
        /// </summary>
        /// <returns></returns>
        public shop createDefault(user user)
        {
            var shop = new shop();
            shop.head = 0;
            shop.able = true;
            shop.quality = 0;
            shop.service = 0;
            shop.priceQuality = 0;
            shop.total_score = 0;
            shop.size = 0;
            shop.sum_score = 0;
            shop.createUserId = user.Id;
            shop.createtime = DateTime.Now;
            return shop;
        }

        public shop getById(string id)
        {
            return db.GetById(id);
        }
        public shop getByName(string name)
        {
            return db.query.Where(d => d.name==name).FirstOrDefault();
        }
        public IQueryable<shop> getLikeName(string name)
        {
            return db.query.Where(d => d.name.Contains(name));
        }
        /// <summary>
        /// 如果参数为假返回全部记录包话无效的没发布的
        /// </summary>
        /// <param name="shopStatus"></param>
        /// <returns></returns>
        public IQueryable<shop> getAll(Boolean shopStatus=true)
        {
            if (shopStatus==true)
            {
                return db.query.Where(d=>d.able==true && d.releaseStep==5);
            }
            else {
                return db.query;
            }
        }

        //取的一个现有商户的id 测试用*****
        public ObjectId getTestId()
        {
            return db.query.FirstOrDefault().Id;
        }

        /// <summary>
        /// 取得店的所有微评
        /// </summary>
        /// <param name="shopId"></param>
        /// <returns></returns>
        public IQueryable<impression> getimpression(string shopId)
        {
            return new impressionC<shop>().getByTargetId(shopId.toOId());
        }
        public sale addSale(shop shop,string content,int type,user user) {
            try
            {
                if (shop.sales == null) { shop.sales = new List<sale>(); }
                sale sale = new sale();
                sale.Id = ObjectId.GenerateNewId();
                
                sale.able = true;
                sale.content = content;
                sale.datetime = DateTime.Now;
                sale.recommendCount = 0;
                sale.userId = user.Id;
                sale.userName = user.name;
                sale.type = type;

                shop.sales.Add(sale);
                db.Save(shop);
                return sale;
            } catch(Exception e){ return null;}
            
        }
        public Boolean setAbleSale(shop shop,string saleId,Boolean able) {
            shop.sales.Single(d => d.Id == ObjectId.Parse(saleId)).able = able;
            db.Save(shop);
            return true;
        }
        public sale delSale(shop shop,string saleId){
            sale sale =shop.sales.Single(d => d.Id == ObjectId.Parse(saleId));
            shop.sales.Remove(sale);
            db.Save(shop);

            return sale;
        }
        /// <summary>
        /// GroupPurchase 团购

        /// </summary>
        /// <returns></returns>
        public IEnumerable<groupPurchase> Getgps(shop shop) {

            DataSession<MongoDataContext, groupPurchase> GPdb = new DataSession<MongoDataContext, groupPurchase>();

                IEnumerable<groupPurchase> gps = GPdb.Where(d=>d.shopId==shop.Id).OrderByDescending(d=>d.datatime);
                return gps;

            
        }
        /// <summary>
        /// 添加comment，并更新shop中相应的积分和花费字段
        /// </summary>
        /// <param name="s"></param>
        /// <param name="content"></param>
        /// <param name="cost"></param>
        /// <param name="quality"></param>
        /// <param name="service"></param>
        /// <param name="priceQuality"></param>
        /// <param name="release"></param>
        /// <returns></returns>
        public comment addComment(ref shop s, string content, int? cost, int? quality, int? service, int? priceQuality,IEnumerable<food> foods,user user, int release=1)
        {
            if (string.IsNullOrWhiteSpace(content) && quality == null && foods.Count() == 0 && cost ==null) { return null; }

            commentC cC = new commentC();
            comment comment = cC.create(s.Id, content,cost, quality, service, priceQuality,  user, DateTime.Now, release);
            if (foods.Count() != 0)
            {
                
                //comment.food = foods.Select(d => new { Id = d.Id.ToString(), name = d.name }).ToJson();
                comment.food = foods.Select(d => d.name).tryJoin(",");
            }
            cC.save(comment);
            //参于人次
            s.comment_number++;

            //updataComment(ref s, comment.cost, comment.quality, comment.service, comment.priceQuality);
            statistics(ref s,comment);

            save(s);
            return comment;
        }
        /// <summary>
        /// 添加图片，不保存
        /// </summary>
        /// <param name="shopId"></param>
        /// <param name="file"></param>
        /// <returns></returns>
        public string addPic(ref shop shop, HttpPostedFileBase file)
        {

            myUpload upload = new myUpload();
            upload.myDirectory = "shopPic";
            upload.imageResize = "640*480";

            try
            {
                string fileName = upload.imageSave(file,true);
                //加到picUrlList字段中
                if (shop.picUrlList == null) shop.picUrlList = new List<string>();
                shop.picUrlList.Add(fileName);
                return fileName;

            }
            catch (Exception ex)
            {
                return null;
                //throw new asMeishiException("fuck" + ex.Message);
            };

            //upload.Dispose();
            //return shop;
        }
        /// <summary>
        /// 增加图片。但不保存
        /// </summary>
        /// <param name="shop"></param>
        /// <param name="file"></param>
        /// <returns></returns>
        public shop addPic(shop shop, HttpPostedFileBase file)
        {

            myUpload upload = new myUpload();
            upload.myDirectory = "shopPic";
            upload.imageResize = "640*480";
            try
            {
                string fileName = upload.imageSave(file,true);
                //加到picUrlList字段中
                if (shop.picUrlList == null) shop.picUrlList = new List<string>();
                shop.picUrlList.Add(fileName);
                db.Save(shop);

            }
            catch (Exception ex)
            {
                throw new asMeishiException("fuck" + ex.Message);
            };

            //upload.Dispose();

            return shop;
        }
        //删除图片,不存保
        public bool delPic(ref shop shop, string picUrl)
        {
            try
            {


                shop.picUrlList.Remove(picUrl);
                myUpload.delImage("shopPic" + picUrl);
                return true;
            }
            catch {
                return false;
            }
            
        }

        /// <summary>
        /// 仅更新shop中菜(food)字段
        /// </summary>
        /// <param name="shopId"></param>
        /// <param name="items"></param>
        public void onlyEditshopFood(ref shop shop, IEnumerable<food> foods)
        {
            string _itemStr = "";
            if (shop.food == null) { shop.food = new List<string>(); } else { shop.food.Clear(); }
            shop.food.Clear();
            foreach (var _item in foods)
            {
                if (_item == null) { continue; }
                _itemStr = "{name:'" + _item.name + "',count:'" + _item.recommendCount + "',date:'" + _item.datatime.ToString() + "'}";
                if (shop.food == null) { shop.food = new List<string>(); }
                shop.food.Add( _itemStr);
            }
        }
        public void onlyEditShopfoodStyle(ref shop shop)
        {
            var dict= publicDictApp.get("shopClass");
            string[] styles = new string[shop.foodStyleList.Count];
            for (var i=0;i<styles.Length;i++) {
                styles[i] = dict[shop.foodStyleList[i]];
            }
            shop.foodStyle = string.Join(",", styles);
        }
        /// <summary>
        /// 修改food表，并更新shop中的food
        /// </summary>
        /// <param name="shop"></param>
        /// <param name="foodsStr"></param>
        public IEnumerable<food> updataFood(ref shop shop, IEnumerable<food> _foods, user user)
        {

            foodC fC = new foodC();

            IEnumerable<food> foods = fC.add(_foods, shop.Id,user);

            onlyEditshopFood(ref shop, _foods);
            return foods;
        }
        /// <summary>
        /// _foodsStr为"xxx","xxx1","xxx2"
        /// </summary>
        /// <param name="shop"></param>
        /// <param name="_foodsStr"></param>
        public IEnumerable<food> updataFood(ref shop shop, string _foodsStr, user user)
        {

            foodC fC = new foodC();

            IEnumerable<food> foods = fC.addstr(_foodsStr, shop.Id,user);

            onlyEditshopFood(ref shop, foods);
            return foods;
        }
        /// <summary>
        /// 更新一个菜与它的一个评价
        /// impressstr
        /// </summary>
        /// <param name="shop"></param>
        /// <param name="_foodsStr"></param>
        public IEnumerable<food> updataFoodAndDetial(ref shop shop, string[] foodNames, string[] intros,string[] price, user user,int release=1)
        {
            if (foodNames == null) { return new List<food>(); }

            List<food> _foods = new List<food>();
            foodC fC = new foodC();
            for (int i =0;i<foodNames.Length;i++) {
                var _food = fC.createDefault();
                if(!string.IsNullOrWhiteSpace(foodNames[i].Trim())){

                        _food.name = foodNames[i].Trim();
                        _food.shopId = shop.Id;
                        try
                        {
                            _food.intro = intros[i].Trim();
                        }
                        catch { continue; }
                        try
                        {
                            _food.price = Convert.ToDouble(price[i].Trim());
                        }
                        catch { _food.price=0; }
                        _foods.Add(_food);
        
                }
                
            }

            IEnumerable<food> foods = fC.add(_foods, shop.Id, user);

            historyC<food> hc = new historyC<food>();

            onlyEditshopFood(ref shop, foods);

            return _foods;
        }
        /// <summary>
        /// 统计打分和cost值
        /// </summary>
        /// <param name="shop"></param>
        /// <param name="cost"></param>
        /// <param name="?"></param>
        public void statistics(ref shop shop,comment comment,Boolean bydb=false)
        {
            commentC cc = new commentC();
            if (bydb == false)
            {
                if (comment.quality != null)
                {
                    
                    shop.quality = (shop.quality * shop.score_number + comment.quality.ToInt().Value) / (shop.score_number+1);
                    shop.service = (shop.service * shop.score_number + comment.service.ToInt().Value) / (shop.score_number+1);
                    shop.priceQuality = (shop.priceQuality * shop.score_number + comment.priceQuality.ToInt().Value) / (shop.score_number+1);
                    shop.total_score += ((shop.quality + shop.service + shop.priceQuality) * (shop.score_number+1)).ToInt().Value;

                    shop.score_number++;

                    shop.sum_score = (shop.quality + shop.service + shop.priceQuality) / 3;
                    
                }

                if(comment.cost!=null && comment.cost!=0){
                    shop.cost_number++;
                    shop.cost = (shop.cost + comment.cost.ToInt().Value) / (shop.cost_number);
                }
                
            }
            else
            {
                var result = cc.statisticsScore(shop.Id);
                var coseResult = cc.statisticsCost(shop.Id);

                //如果。有提交
                if (comment != null)
                {
                    if (comment.quality != null) { shop.score_number++; }
                    if (comment.cost != null && comment.cost != 0) { shop.cost_number++; }
                }

                if (result.GetResults().Any() != false)
                {
                    shop.quality = (double)((BsonDocument)(result.GetResults().ElementAt(0).ElementAt(1).Value)).GetElement("Q").Value;
                    shop.service = (double)((BsonDocument)(result.GetResults().ElementAt(0).ElementAt(1).Value)).GetElement("S").Value;
                    shop.priceQuality = (double)((BsonDocument)(result.GetResults().ElementAt(0).ElementAt(1).Value)).GetElement("E").Value;
                    shop.total_score = ((double)((BsonDocument)(result.GetResults().ElementAt(0).ElementAt(1).Value)).GetElement("totalScore").Value).ToInt().Value;

                    shop.score_number = ((double)((BsonDocument)(result.GetResults().ElementAt(0).ElementAt(1).Value)).GetElement("count").Value).ToInt().Value;
                    shop.sum_score = (double)(shop.total_score) / (double)(shop.score_number) / 3;
                    
                }
                else {
                    shop.quality = 0;
                    shop.service = 0;
                    shop.priceQuality = 0;
                    shop.score_number = 0;
                    shop.total_score = 0;
                    shop.sum_score = 0;
                }


                //if (comment!=null &&(comment.cost != null || comment.cost == 0) )
                //{
                    if(coseResult.GetResults().Any()){
                        shop.cost = (double)((BsonDocument)(coseResult.GetResults().ElementAt(0).ElementAt(1).Value)).GetElement("C").Value;
                        shop.cost_number = (int)((BsonDocument)(coseResult.GetResults().ElementAt(0).ElementAt(1).Value)).GetElement("count").Value.ToInt().Value;
                    }else{
                        shop.cost=0;
                        shop.cost_number=0;
                    }
                //}
            }
                //shop.quality += quality.ToInt().Value;
                //shop.service += service.ToInt().Value;
                //shop.priceQuality += priceQuality.ToInt().Value;
                //shop.score_number++;
                ////总分
                //shop.total_score += shop.quality + shop.service + shop.priceQuality + shop.total_score;
                ////平均分
                //shop.sum_score = shop.total_score / shop.score_number;


        }
        /// <summary>
        /// 设置打分和cost值总值及打分数次
        /// </summary>
        /// <param name="shop"></param>
        /// <param name="cost"></param>
        /// <param name="?"></param>
        [Obsolete("已经放弃总值的算法，不利及排名")]
        public void updataComment(ref shop shop, int? cost, int? quality, int? service, int? priceQuality)
        {
            if (cost != null)
            {
                shop.cost += cost.ToInt().Value;
                shop.cost_number++;
            }
            if (quality != null && service != null && priceQuality != null)
            {
                shop.quality += quality.ToInt().Value;
                shop.service += service.ToInt().Value;
                shop.priceQuality += priceQuality.ToInt().Value;
                shop.score_number++;
                //总分
                //shop.total_score += shop.quality + shop.service + shop.priceQuality + shop.total_score;
                //平均分
                shop.sum_score = shop.total_score / shop.score_number;
            }
            shop.comment_number++;

        }

        public void save(shop shop)
        {
            db.Save(shop);
        }
        //Q缺省时 取出所有发布并有效的店数
        public long sum(Dictionary<string,object> Q = null)
        {

            if (Q == null)
            {

                return db.count(ableQuery());

            }


            return db.count(Q);
        }

        private QueryDocument ableQuery() {
            var  rlq = new QueryDocument("RL",5);
            var aq = new QueryDocument("able",true);
            aq.Add(rlq);
            return aq;

        }
        //Q缺省时 取出所有发布并有效的店数
        public long sum(IMongoQuery Q)
        {

            if (Q == null)
            {

                return db.count(ableQuery());

            }

            return db.count(Q);
        }
        
        public void del(ObjectId Id){
            db.Delete(Id);
        }

        public IEnumerable<shop> getByUserByUnrelease(user user){
            return db.Where(d => d.createUserId == user.Id && d.releaseStep != 5);
        }
        public IQueryable<shop> sift(IMongoQuery Q)
        {
            
            var QQ = (Q as QueryDocument);

            //using(MongoSession<shop> db2 = new MongoSession<shop>()){
            if (Q==null) {
                return db.query;
            }

            return db.Where(QQ);

        }
        
    }



}
